package com.zhiyin.seal.controller;

import com.google.common.collect.Lists;
import com.zhiyin.seal.anno.OperateLog;
import com.zhiyin.seal.config.MyWXPayConfig;
import com.zhiyin.seal.entity.bo.*;
import com.zhiyin.seal.entity.dto.RechargePackageDTO;
import com.zhiyin.seal.entity.dto.RechargeParamsDTO;
import com.zhiyin.seal.entity.dto.ResponseDTO;
import com.zhiyin.seal.entity.vo.*;
import com.zhiyin.seal.payment.WXPay;
import com.zhiyin.seal.payment.WXPayConstants;
import com.zhiyin.seal.payment.WXPayUtil;
import com.zhiyin.seal.service.CostService;
import com.zhiyin.seal.service.SealService;
import com.zhiyin.seal.service.UserService;
import com.zhiyin.seal.util.BeanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 费用业务控制器
 */
@RestController
@RequestMapping("/cost")
public class CostController {

    @Autowired
    CostService costService;

    @Autowired
    UserService userService;

    @Autowired
    SealService sealService;

    @Autowired
    private HttpServletRequest request;

    @Autowired(required = false)
    private HttpServletResponse response;


    @GetMapping("/rechargepackagelist")
    public ResponseDTO<List<RechargePackageVo>> getRechargePackageList(){
        return ResponseDTO.succData(BeanUtil.copyList(costService.getRechargePackageList(),RechargePackageVo.class));
    }

    @GetMapping("/recharge/package/list/all")
    public ResponseDTO<List<RechargePackageVo>> getAllRechargePackageList(){
        return ResponseDTO.succData(BeanUtil.copyList(costService.getAllRechargePackageList(),RechargePackageVo.class));
    }

    @OperateLog(description = "添加套餐包")
    @PostMapping("/recharge/package/add")
    public ResponseDTO<Boolean> addRechargePackage(@RequestBody RechargePackageDTO rechargePackageDTO){
        return ResponseDTO.succData(costService.addRechargePackage(BeanUtil.copy(rechargePackageDTO,RechargePackageBo.class)));
    }

    @OperateLog(description = "更新套餐包")
    @PostMapping("/recharge/package/update")
    public ResponseDTO<Boolean> updateRechargePackage(@RequestBody RechargePackageDTO rechargePackageDTO){
        return ResponseDTO.succData(costService.updateRechargePackage(BeanUtil.copy(rechargePackageDTO,RechargePackageBo.class)));
    }

    @GetMapping("/recharge/record/list/all")
    public ResponseDTO<List<RechargeRecordWebVo>> getAllRechargeRecord(){
        List<RechargeRecordWebVo> rechargeRecordVoList = BeanUtil.copyList(costService.getAllRechargeRecordList(),RechargeRecordWebVo.class);
        if(rechargeRecordVoList != null){
            for (RechargeRecordVo rechargeRecordVo : rechargeRecordVoList) {
                rechargeRecordVo.setPackageVo(BeanUtil.copy(costService.getRechargePackage(rechargeRecordVo.getPackageId()),RechargePackageVo.class));
            }
        }
        return ResponseDTO.succData(rechargeRecordVoList);
    }

    @GetMapping("/rechargerecordlist")
    public ResponseDTO<List<RechargeRecordVo>> getRechargeRecord(@RequestParam Long userId){
        List<RechargeRecordVo> rechargeRecordVoList = BeanUtil.copyList(costService.getRechargeRecordList(userId),RechargeRecordVo.class);
        if(rechargeRecordVoList != null){
            for (RechargeRecordVo rechargeRecordVo : rechargeRecordVoList) {
                rechargeRecordVo.setPackageVo(BeanUtil.copy(costService.getRechargePackage(rechargeRecordVo.getPackageId()),RechargePackageVo.class));
            }
        }
        return ResponseDTO.succData(rechargeRecordVoList);
    }

    @GetMapping("/rechargerecordlist/company")
    public ResponseDTO<List<RechargeRecordVo>> getRechargeRecordByCompany(@RequestParam Long companyId){
        List<RechargeRecordVo> rechargeRecordVoList = BeanUtil.copyList(costService.getRechargeRecordListByCompany(companyId),RechargeRecordVo.class);
        if(rechargeRecordVoList != null){
            for (RechargeRecordVo rechargeRecordVo : rechargeRecordVoList) {
                rechargeRecordVo.setPackageVo(BeanUtil.copy(costService.getRechargePackage(rechargeRecordVo.getPackageId()),RechargePackageVo.class));
            }
        }
        return ResponseDTO.succData(rechargeRecordVoList);
    }

    @GetMapping("/rechargerecorddetaillist")
    public ResponseDTO<List<RechargeRecordDetailVo>> getRechargeRecordDetail(@RequestParam Long recordId){
        RechargeRecordBo rechargeRecordBo = costService.getRechargeRecordById(recordId);
        if(rechargeRecordBo == null){
            return ResponseDTO.succData(null);
        }
        List<RechargeRecordDetailVo> rechargeRecordDetailVoList = BeanUtil.copyList(costService.getRechargeRecordDetailList(recordId), RechargeRecordDetailVo.class);
        if(rechargeRecordDetailVoList != null){
            for (RechargeRecordDetailVo rechargeRecordDetailVo : rechargeRecordDetailVoList) {
                rechargeRecordDetailVo.setSealVo(BeanUtil.copy(sealService.getSealByIdAndCompany(rechargeRecordDetailVo.getSealId(),rechargeRecordBo.getCompanyId()), SealVo.class));
            }
        }

        return ResponseDTO.succData(rechargeRecordDetailVoList);
    }

    @PostMapping("/order")
    public Map<String,String> order(@RequestBody RechargeParamsDTO rechargeParamsDTO){
        UserBo userBo = userService.getUserInfo(rechargeParamsDTO.getOpenId());
        if(userBo == null){
            Map<String,String> payMap = new HashMap<String,String>();
            payMap.put("return_code","FAIL-01");
            payMap.put("result_code","FAIL-01");

            return payMap;
        }
        RechargePackageBo rechargePackageBo = costService.getRechargePackage(rechargeParamsDTO.getRechargePackageId());
        List<String> sealIdList = rechargeParamsDTO.getSealIdList();
        // 生成订单编号
        SimpleDateFormat SDF_YYMMDDHHMMSS = new SimpleDateFormat("yyMMddHHmmss");
        String orderNumber = "QSYZ" + SDF_YYMMDDHHMMSS.format(new Date())+ String.valueOf(new Random().nextInt(899999) + 100000);
        RechargeRecordBo rechargeRecordBo = new RechargeRecordBo();
        rechargeRecordBo.setOrderNumber(orderNumber);
        rechargeRecordBo.setPackageId(rechargeParamsDTO.getRechargePackageId());
        rechargeRecordBo.setSealCount(sealIdList.size());
        rechargeRecordBo.setSealIds(String.join(",",sealIdList));
        Double money = rechargePackageBo.getPrice() * sealIdList.size();
        rechargeRecordBo.setTotalAmount(money);
        rechargeRecordBo.setRechargeMode(1);
        Long companyId = rechargeParamsDTO.getCompanyId();
        if(companyId == null){
            Long sealId = Long.parseLong(sealIdList.get(0));
            SealBo sealBo = sealService.getSeal(sealId);
            if(sealBo != null){
                companyId = sealBo.getCompanyId();
            } else {
                companyId = 0l;
            }
        }
        rechargeRecordBo.setCompanyId(companyId);
        rechargeRecordBo.setCreateUser(userBo.getId());
        Boolean result = costService.addOrder(rechargeRecordBo);
        if(result){
            // System.out.println("===============创建订单成功================");
        } else {
            // System.out.println("===============创建订单失败================");
            Map<String,String> payMap = new HashMap<String,String>();
            payMap.put("return_code","FAIL-01");
            payMap.put("result_code","FAIL-01");

            return payMap;
        }
        try {
            //System.out.println("===============开始下单================");
            MyWXPayConfig config = new MyWXPayConfig();
            WXPay wxpay = new WXPay(config,null,false,false);
            Map<String, String> data = new HashMap<String, String>();
            data.put("body", "青石印章管家-服务费充值");
            data.put("out_trade_no", orderNumber);
            data.put("fee_type", "CNY");
            // 金额转换为分，去掉小数点
            String total_fee= BigDecimal.valueOf(money).multiply(BigDecimal.valueOf(100)).setScale(0, BigDecimal.ROUND_HALF_UP).toString();
            data.put("total_fee", total_fee);
            data.put("spbill_create_ip", WXPayUtil.getRemoteAddrIp(request));
            data.put("notify_url", "https://www.baiheyz.com/smartsealservice/cost/notify");
            data.put("trade_type", "JSAPI");
            data.put("openid", rechargeParamsDTO.getOpenId());
            data.put("receipt","Y");
            // 支付参数封装完成，调用微信统一下单接口
            Map<String, String> resp = wxpay.unifiedOrder(data);
            //判断下单是否成功
            if("SUCCESS".equals(resp.get("result_code"))){
                // System.out.println("===============下单成功！================");
                Map<String,String> payMap = new HashMap<String,String>();
                payMap.put("appId",config.getAppID());
                payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
                payMap.put("nonceStr", WXPayUtil.generateNonceStr());
                payMap.put("package", "prepay_id=" + resp.get("prepay_id"));
                payMap.put("signType","HMAC-SHA256");
                String paySign = WXPayUtil.generateSignature(payMap, WXPayConstants.KEY, WXPayConstants.SignType.HMACSHA256);
                payMap.put("paySign",paySign);
                payMap.put("return_code",resp.get("return_code"));
                payMap.put("result_code",resp.get("result_code"));
                payMap.put("out_trade_no",orderNumber);

                return payMap;
            } else {
                // System.out.println("下单失败！");
                // System.out.println(resp);
            }
        } catch (Exception e) {
            e.printStackTrace();
            // System.out.println("下单异常！");
        }

        Map<String,String> payMap = new HashMap<String,String>();
        payMap.put("return_code","FAIL-01");
        payMap.put("result_code","FAIL-01");

        return payMap;
    }

    @RequestMapping(value = "/query",method = RequestMethod.GET)
    public Map<String, String> orderQuery(@RequestParam String tradeNo){
        try {
            // System.out.println("===============查询订单================");
            MyWXPayConfig config = new MyWXPayConfig();
            WXPay wxpay = new WXPay(config,null,false,false);
            Map<String, String> data = new HashMap<String, String>();
            data.put("out_trade_no", tradeNo);
            Map<String, String> resp = wxpay.orderQuery(data);
            // 判断交易状态是否成功
            if("SUCCESS".equals(resp.get("trade_state"))){
                // System.out.println("===============订单交易成功！================");
                // 查询订单
                RechargeRecordBo rechargeRecordBo = costService.queryOrder(tradeNo);
                if(rechargeRecordBo != null){
                    // 更新支付状态为：交易成功
                    costService.updatePayStatus(tradeNo,1);
                    // 查询是否存在订单明细
                    List<RechargeRecordDetailBo> recordDetailBoList = costService.getRechargeRecordDetailList(rechargeRecordBo.getId());
                    if(recordDetailBoList.size() == 0){
                        // 构造订单明细
                        recordDetailBoList = Lists.newArrayList();
                        String sealIds = rechargeRecordBo.getSealIds();
                        String[] sealIdList = sealIds.split(",");
                        // 查询套餐
                        RechargePackageBo rechargePackageBo = costService.getRechargePackage(rechargeRecordBo.getPackageId());
                        // 计算月数
                        Integer totalMonth = rechargePackageBo.getMonthNumber() + rechargePackageBo.getGiveMonth();
                        for (int i = 0; i < sealIdList.length; i++) {
                            Long sealId = Long.parseLong(sealIdList[i]);
                            SealBo sealBo = sealService.getSeal(sealId);

                            RechargeRecordDetailBo recordDetailBo = new RechargeRecordDetailBo();
                            recordDetailBo.setRecordId(rechargeRecordBo.getId());
                            recordDetailBo.setSealId(sealId);
                            recordDetailBo.setLastServiceTime(sealBo.getServiceTime());
                            // 计算服务费时间
                            Calendar calendar = Calendar.getInstance();
                            Date now = new Date();
                            // 如果之前的服务器时间大于当前时间，则服务费的起始时间为上次的服务费时间
                            if(sealBo.getServiceTime().getTime() - now.getTime() > 0){
                                calendar.setTime(sealBo.getServiceTime());
                            }
                            calendar.add(Calendar.MONTH,totalMonth);
                            recordDetailBo.setCurrentServiceTime(calendar.getTime());
                            recordDetailBo.setAmount(rechargePackageBo.getPrice());
                            recordDetailBoList.add(recordDetailBo);
                        }
                        // 插入订单明细
                        costService.addOrderDetail(recordDetailBoList);
                    }
                    // 根据订单明细更新印章服务费
                    costService.updateSealServiceTime(recordDetailBoList);
                }
            } else {
                // 更新支付状态为：交易失败
                costService.updatePayStatus(tradeNo,2);
                // System.out.println("===============交易失败！================");
                // System.out.println(resp);
            }

            return resp;
        }catch (Exception e) {
            e.printStackTrace();
        }

        Map<String, String> resp = new HashMap<String,String>();
        resp.put("return_code","FAIL-01");
        resp.put("result_code","FAIL-01");

        return resp;
    }

    @RequestMapping(value = "/notify",method = RequestMethod.POST)
    public void payNotify(){
        try {
            // System.out.println("===============订单支付通知================");
            //读取XML数据
            byte[] buffer = new byte[request.getContentLength()];
            ServletInputStream sis = request.getInputStream();
            sis.read(buffer, 0, buffer.length);
            String notifyData = new String(buffer);
            //XML转字典
            Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);

            MyWXPayConfig config = new MyWXPayConfig();
            WXPay wxpay = new WXPay(config);
            //验证签名
            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
                // 判断支付结果
                if("SUCCESS".equals(notifyMap.get("result_code"))){
                    // System.out.println("===============订单交易成功！================");
                } else {
                    // System.out.println("===============交易失败！================");
                    // System.out.println(notifyMap);
                }
            }
            else {
                // 签名错误，如果数据里没有sign字段，也认为是签名错误
                // System.out.println("支付通知签名验证失败!");
                // System.out.println(notifyMap);
            }

        } catch (Exception ex){

        } finally {
            response.setContentType("text/xml");
            Map<String,String> map = new HashMap<String,String>();
            map.put("return_code", "SUCCESS");
            map.put("return_msg", "OK");

            String resXml = null;
            try {
                resXml = WXPayUtil.mapToXml(map);
                response.getWriter().write(resXml);
                response.flushBuffer();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
